package com.mazaiting.patch

import name.fraser.neil.plaintext.diff_match_patch
import java.io.*
import java.util.*

const val FILE1 = "index.android"
const val FILE2 = "index1.android"
const val FILE3 = "$FILE2-$FILE1.patch"

const val FILE_DIR = "E:\\android\\React-Native-Study\\Unpacking\\bundle\\"
const val SUFFIX = ".bundle"

object Patch {
  @JvmStatic
  fun main(args: Array<String>) {
    val file1 = "$FILE_DIR$FILE1$SUFFIX"
    val file2 = "$FILE_DIR$FILE2$SUFFIX"
    val file3 = "$FILE_DIR$FILE3"
    val patch = productPatch(file1, file2)
    
    productFile(file1, file3, patch)
  }
  
  /**
   * 生成文件
   * @param fileOri 源文件
   * @param fileDest 目标文件
   * @param patchString 差异字符串
   */
  private fun productFile(fileOri: String, fileDest: String, patchString: String?) {
    // 创建对象
    val patch = diff_match_patch()
    // 读取文件
    val file1 = readFile(fileOri)
    // 获取补丁内容
    val patchText = patch.patch_fromText(patchString)
    // 应用补丁
    val patchApply = patch.patch_apply(LinkedList(patchText), file1)
    
    println("===============================================")
    println("结果：" + patchApply[0])
    // 写入文件内容
    writeResult(fileDest, patchApply[0].toString())
    println("===============================================")
    // 获取执行结果数组，true为成功，false为失败
    val patchResult: BooleanArray = patchApply[1] as BooleanArray
    val result = StringBuilder()
    patchResult.forEach { result.append("$it  ") }
    
    println("result: $result")
  }
  
  /**
   * 写入文件
   * @param fileDest 目标文件
   * @param string 文件内容
   */
  private fun writeResult(fileDest: String, string: String) {
    // Read a file from disk and return the text contents.
    val output = FileWriter(fileDest)
    val writer = BufferedWriter(output)
    try {
      writer.write(string)
    } finally {
      writer.close()
      output.close()
    }
  }
  
  /**
   * 生成差异patch
   * @param fileOri 源文件
   * @param fileDest 目标文件
   * @return 差异字符串
   */
  private fun productPatch(fileOri: String, fileDest: String): String? {
    // 创建对象
    val diff = diff_match_patch()
    // 读取基础文件内容
    val file1 = readFile(fileOri)
    // 读取目标文件内容
    val file2 = readFile(fileDest)
    // 进行差异化
    val diffString = diff.diff_main(file1, file2, true)
    // 数组长度大于2执行
    if (diffString.size > 2) {
      diff.diff_cleanupSemantic(diffString)
    }
    
    println(diffString)
    
    println("===============================================")
    // 生成patch内容
    val patchString = diff.patch_make(file1, diffString)
    println(patchString)
    
    println("===============================================")
    // 将patch内容转为字符串
    val patchText = diff.patch_toText(patchString)
    println(patchText)
    
    return patchText
  }
  
  /**
   * 读取文件
   * @param filename 文件名
   * @return 文件内容
   */
  @Throws(IOException::class)
  private fun readFile(filename: String): String {
    // Read a file from disk and return the text contents.
    val sb = StringBuilder()
    val input = FileReader(filename)
    val bufRead = BufferedReader(input)
    try {
      var line = bufRead.readLine()
      while (line != null) {
        sb.append(line).append('\n')
        line = bufRead.readLine()
      }
    } finally {
      bufRead.close()
      input.close()
    }
    return sb.toString()
  }
}
